
#include <fcntl.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <unistd.h>
#include "ka-io/stream.h"

using namespace io;

void *_fildes_to_handle(int filedes) {
    union {void *p; int i;} u;
    u.i = filedes;
    return u.p;
}

int _handle_to_fildes(void *handle) {
    union {void *p; int i;} u;
    u.p = handle;
    return u.i;
}

void _destroy_handle(void *handle) {
    (void)handle;
    // no need
}

bool _valid_handle(void *handle) {
    return handle != NULL;
}

FileStream::FileStream(const char *filePath, uint32_t flags)
: _handle(NULL) {
    
    int oflags = 0;
    
    if ((flags & READ) != 0) {
        oflags = O_RDONLY;
    }
    if ((flags & WRITE) != 0) {
        oflags = oflags==O_RDONLY ? O_RDWR : O_WRONLY;
    }
    
    oflags |= O_CREAT;
    
    int filedes = open(filePath, oflags, 0);
    _handle = _fildes_to_handle(filedes);
}

FileStream::~FileStream() {
    close();
}

size_t FileStream::read(void *dest, size_t byteCount) {
    int filedes = _handle_to_fildes(_handle);
    size_t totalCount = 0;
    while (totalCount < byteCount) {
        ssize_t res = ::read(filedes, (uint8_t *)dest+totalCount, byteCount-totalCount);
        if (res <= 0) {
            /* eof or error */
            break;
        }
        totalCount += res;
    }
    return totalCount;
}

size_t FileStream::write(const void *source, size_t byteCount) {
    int filedes = _handle_to_fildes(_handle);
    size_t totalCount = 0;
    while (totalCount < byteCount) {
        ssize_t res = ::write(filedes, (uint8_t *)source + totalCount, byteCount-totalCount);
        if (res <= 0) {
            /* error */
            break;
        }
        totalCount += res;
    }
    return totalCount;
}

void FileStream::close() {
    if (_valid_handle(_handle)) {
        int filedes = _handle_to_fildes(_handle);
        ::close(filedes);
        _destroy_handle(_handle);
        _handle = NULL;
    }
}